<script setup lang="ts">
import type { AppPosition, AppTypeProps } from '@/types';

import {
  type ComponentInternalInstance,
  type DefineComponent,
  getCurrentInstance,
  onMounted,
  onUnmounted,
  type PropType,
  ref,
  shallowRef,
  unref,
  watch,
} from 'vue';

import components from '@/router/routes/pages';
import { useAppStore } from '@/store';
import { X,Minus,Maximize2,Minimize2 } from 'lucide-vue-next';

defineOptions({
  name: 'App',
});

const props = defineProps({
  app: {
    default: () => ({}),
    type: Object as PropType<AppTypeProps>,
  },
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
interface DEFINE_COMPONENT {
  [key: string]: any; // 字段扩展声明
}

const dynamicComponents = shallowRef<DEFINE_COMPONENT>(components);

// 加载组件
const loadComponent = (component: string) => {
  return (unref(dynamicComponents)[component] ||
    unref(dynamicComponents).NotFound) as DefineComponent;
};

const appStore = useAppStore();
const appData = ref(props.app);
// const activeIndex = ref(20);
// const defaultIndex = ref(10);
const isBoxMoving = ref(false);
const isBoxResizing = ref(false);
const isFullScreen = ref(false);
const isMaxShowing = ref(false);
const moveDirection = ref<string>();
const link = ref<string>();
const nowRect = ref<AppPosition>({
  bottom: 100,
  left: 100,
  right: 100,
  top: 100,
});
const startPosition = ref({ x: 0, y: 0 });
const startRect = ref({
  bottom: 0,
  left: 0,
  right: 0,
  top: 0,
});

/**
 * @description: 标题栏被双击 缩放
 */
const appBarDoubleClicked = () => {
  if (props.app.disableResize) {
    return;
  }
  isMaxShowing.value = !isMaxShowing.value;
  if (!isMaxShowing.value) {
    isFullScreen.value = false;
  }
};

/**
 * @description: 隐藏当前应用
 */
const hideApp = () => {
  appStore.hideApp(props.app);
};
/**
 * @description: 关闭当前应用
 */
const closeApp = () => {
  appStore.closeApp(props.app);
};

/**
 * @description: 监听APP发送的事件 转发或处理到桌面组件中
 */
const appEvent = (e: any) => {
  switch (e.event) {
    case 'windowMaxSize': {
      if (props.app.disableResize) {
        return;
      }
      isMaxShowing.value = true;
      isFullScreen.value = false;
      break;
    }
    case 'windowNormalSize': {
      if (props.app.disableResize) {
        return;
      }
      isMaxShowing.value = false;
      isFullScreen.value = false;
      break;
    }
    case 'windowFullSize': {
      if (props.app.disableResize) {
        return;
      }
      isFullScreen.value = true;
      isMaxShowing.value = true;
      break;
    }
    case 'windowMinSize': {
      hideApp();
      break;
    }
    case 'windowClose': {
      closeApp();
      break;
    }
    case 'openApp': {
      if (e.data && e.app) {
        appStore.openWithData({
          app: proxy?.$tool.getAppByKey(e.app),
          data: e.data,
        });
      } else {
        appStore.openApp(proxy?.$tool.getAppByKey(e.app));
      }
      break;
    }
    case 'closeApp': {
      if (e.pid) {
        appStore.closeWithPid(e.pid);
      }
      if (e.app) {
        appStore.closeApp(proxy?.$tool.getAppByKey(e.app));
      }
      break;
    }
    case 'setWindowTitle': {
      appData.value.title = e.title || props.app.title;
      break;
    }
    default:
  }
};

/**
 * @description: 返回应用配置的样式类
 */
const getExtBoxClasses = () => {
  let str = '';
  if (!isBoxResizing.value && !isBoxMoving.value) {
    str += 'box-animation ';
  }
  if (isMaxShowing.value) {
    str += 'isMaxShowing ';
  }
  if (isFullScreen.value) {
    str += 'isFullScreen ';
  }
  if (props.app.disableResize) {
    str += 'resize-disabled ';
  }
  if (
    appStore.openAppList[appStore.openAppList.length - 1]?.pid === props.app.pid
  ) {
    str += 'isTop ';
  }
  return str;
};

const mouseLeave = () => {
  isBoxMoving.value = false;
  isBoxResizing.value = false;
  moveDirection.value = '';
};

const mouseMove = (e: MouseEvent) => {
  if (isBoxResizing.value) {
    isFullScreen.value = false;
    isMaxShowing.value = false;
    switch (moveDirection.value) {
      case 'box-top-left': {
        nowRect.value.top =
          startRect.value.top + (e.clientY - startPosition.value.y);
        nowRect.value.left =
          startRect.value.left + (e.clientX - startPosition.value.x);
        break;
      }
      case 'box-top-center': {
        nowRect.value.top =
          startRect.value.top + (e.clientY - startPosition.value.y);
        break;
      }
      case 'box-top-right': {
        nowRect.value.top =
          startRect.value.top + (e.clientY - startPosition.value.y);
        nowRect.value.right =
          startRect.value.right - (e.clientX - startPosition.value.x);
        break;
      }
      case 'box-center-left': {
        nowRect.value.left =
          startRect.value.left + (e.clientX - startPosition.value.x);
        break;
      }
      case 'box-bottom-left': {
        nowRect.value.left =
          startRect.value.left + (e.clientX - startPosition.value.x);
        nowRect.value.bottom =
          startRect.value.bottom - (e.clientY - startPosition.value.y);
        break;
      }
      case 'box-bottom-center': {
        nowRect.value.bottom =
          startRect.value.bottom - (e.clientY - startPosition.value.y);
        break;
      }
      case 'box-center-right': {
        nowRect.value.right =
          startRect.value.right - (e.clientX - startPosition.value.x);
        break;
      }
      case 'box-bottom-right': {
        nowRect.value.right =
          startRect.value.right - (e.clientX - startPosition.value.x);
        nowRect.value.bottom =
          startRect.value.bottom - (e.clientY - startPosition.value.y);
        break;
      }
      default:
    }
    return;
  }
  if (isBoxMoving.value) {
    isFullScreen.value = false;
    isMaxShowing.value = false;
    nowRect.value.left =
      startRect.value.left + (e.clientX - startPosition.value.x);
    nowRect.value.right =
      startRect.value.right - (e.clientX - startPosition.value.x);
    nowRect.value.top =
      startRect.value.top + (e.clientY - startPosition.value.y);
    nowRect.value.bottom =
      startRect.value.bottom - (e.clientY - startPosition.value.y);
  }
};

const mouseUp = () => {
  isBoxMoving.value = false;
  isBoxResizing.value = false;
  moveDirection.value = '';
};

const showThisApp = () => {
  appStore.showApp(props.app);
};

/**
 * @description: 鼠标按下
 */
const positionMouseDown = (e: MouseEvent) => {
  showThisApp();
  if (isFullScreen.value || isMaxShowing.value) {
    return;
  }
  startRect.value = {
    bottom: nowRect.value.bottom,
    left: nowRect.value.left,
    right: nowRect.value.right,
    top: nowRect.value.top,
  };
  startPosition.value.x = e.clientX;
  startPosition.value.y = e.clientY;
  isBoxMoving.value = true;
};

const resizeMouseDown = (e: MouseEvent) => {
  if (props.app.disableResize) {
    return;
  }
  showThisApp();
  if (isFullScreen.value || isMaxShowing.value) {
    return;
  }
  startRect.value = {
    bottom: nowRect.value.bottom,
    left: nowRect.value.left,
    right: nowRect.value.right,
    top: nowRect.value.top,
  };
  startPosition.value.x = e.clientX;
  startPosition.value.y = e.clientY;
  isBoxResizing.value = true;
  moveDirection.value = (e.target as Element).className;
};

const setReact = () => {
  if (props.app.width) {
    nowRect.value.left = nowRect.value.right =
      (document.body.clientWidth - props.app.width) / 2;
  }
  if (props.app.height) {
    nowRect.value.bottom = (document.body.clientHeight - props.app.height) / 2;
    nowRect.value.top = (document.body.clientHeight - props.app.height) / 2;
  }
};

/**
 * @description: 监听APP发送的事件 转发或处理到桌面组件中
 */
const appResize = (size: { left: number; right: number }) => {
  Object.assign(nowRect.value, size);
  // setReact();
};

const emits = defineEmits(['change'])

// 添加/删除书签
const toggleBookmark = () => {
  console.log('toggleBookmark')
}

const appChange = (data: { url: string }) => {
  link.value = data.url
}
/**
 * @description: 全屏切换
 */
const switchFullScreen = () => {
  if (props.app.disableResize) {
    return;
  }
  isFullScreen.value = !isFullScreen.value;
  isMaxShowing.value = !!isFullScreen.value;
  if (isFullScreen.value) {
    nowRect.value = {
      bottom: 0,
      left: 0,
      right: 0,
      top: 0,
    };
  } else {
    setReact();
  }
};

const navigate = (url: string | undefined) => {
  if (!url) return
  const fullUrl = url.startsWith('http://') || url.startsWith('https://') 
    ? url
    : `https://${url}`
  
  // 更新地址栏
  link.value = fullUrl
}

onMounted(() => {
  setReact();
  window.addEventListener('resize', setReact);
});

onUnmounted(() => {
  // 移除监听事件
  window.removeEventListener('resize', setReact);
});

watch(
  () => props.app,
  (val: AppTypeProps) => {
    appData.value = Object.assign({ title: appData.value?.title }, val);
  },
  { deep: true },
);

watch(
  () => [isFullScreen.value, isMaxShowing.value],
  (value) => {
    if (value[0]) {
      appStore.setWindowState('fullscreen');
    } else if (value[1]) {
      appStore.setWindowState('maximize');
    } else {
      appStore.setWindowState('normal');
    }
  },
);
</script>

<template>
  <div
    :style="{
      pointerEvents: isBoxResizing || isBoxMoving ? 'auto' : 'none',
      zIndex: isFullScreen ? 999 : app.isTop ? 98 : 88,
    }"
    class="moveBg"
    @mouseleave.stop="mouseLeave"
    @mousemove="mouseMove"
    @mouseup="mouseUp"
  >
    <div
      :class="getExtBoxClasses()"
      :style="{
        left: `${nowRect.left}px`,
        top: `${nowRect.top}px`,
        bottom: `${nowRect.bottom}px`,
        right: `${nowRect.right}px`,
      }"
      class="box"
    >
      <div class="box-top">
        <div class="box-top-left" @mousedown="resizeMouseDown"></div>
        <div class="box-top-center" @mousedown="resizeMouseDown"></div>
        <div class="box-top-right" @mousedown="resizeMouseDown"></div>
      </div>
      <div class="box-center">
        <div class="box-center-left" @mousedown="resizeMouseDown"></div>
        <div class="box-center-center loader" @mousedown.stop="showThisApp">
          <div
            :style="{ backgroundColor: app.titleBgColor }"
            class="app-bar"
            @dblclick="appBarDoubleClicked"
            @mousedown.stop="positionMouseDown"
          >
            <div class="controll">
              <div class="icon-box close" @click.stop="closeApp">
                <X :size="12" class="icon" />
              </div>
              <div class="icon-box min" @click.stop="hideApp">
                <Minus :size="12" class="icon" />
              </div>
              <div
                :class="['icon-box', 'full', {'full-disabled':app.disableResize}]"
                @click="switchFullScreen"
              >
                <Maximize2 :size="12" class="icon" v-if="!isFullScreen && !isMaxShowing" />
                <Minimize2 :size="12" class="icon" v-if="isFullScreen || isMaxShowing" />
              </div>
            </div>
            <div class="browser" v-if="app.key==='work_browser'">
              <div class="navigation">
                  <span class="text-lg icon-[mdi--chevron-left]"></span>
                  <span class="text-lg icon-[mdi--chevron-right]"></span>
              </div>
              <div class="address">
                <input v-model="link" placeholder="about:blank" type="text" class="link" @dblclick.stop="" @keyup.enter="navigate(link)" />
                <span class="refresh icon-[mdi--refresh]"></span>
              </div>
              <div class="extra">
                <span 
                  class="icon-[mdi--bookmark-outline] cursor-pointer hover:text-blue-500 mr-2" 
                  title="书签"
                  @click="toggleBookmark"
                ></span>
                <span class="icon-[mdi--plus] cursor-pointer hover:text-blue-500" title="新增标签页"></span>
              </div>
            </div>
            <div :style="{ color: app.titleColor }" class="title" v-else>
              {{ appData.title || app.title }}
            </div>
          </div>
          <div class="app-body">
            <component
              :is="loadComponent(`${app.component}`)"
              :app="app"
              :is-box-resizing="isBoxResizing"
              :is-full-screen="isFullScreen"
              :is-max-showing="isMaxShowing"
              :now-rect="nowRect"
              :ref="`appElRef-${app.key}`"
              @api="appEvent"
              @resize="appResize"
              @change="appChange"
            />
          </div>
        </div>
        <div class="box-center-right" @mousedown="resizeMouseDown"></div>
      </div>
      <div class="box-bottom">
        <div class="box-bottom-left" @mousedown="resizeMouseDown"></div>
        <div class="box-bottom-center" @mousedown="resizeMouseDown"></div>
        <div class="box-bottom-right" @mousedown="resizeMouseDown"></div>
      </div>
    </div>
  </div>
</template>
<style scoped lang="scss">
@import url('./css/App.scss');

.bookmark-list {
  padding: 10px;
  
  .bookmark-item {
    display: flex;
    align-items: center;
    padding: 8px;
    margin-bottom: 8px;
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.2s;

    &:hover {
      background-color: var(--el-fill-color-light);
    }

    i {
      margin-right: 8px;
      color: var(--el-color-primary);
    }

    .title {
      flex: 1;
      margin-right: 8px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .url {
      flex: 2;
      color: var(--el-text-color-secondary);
      font-size: 0.9em;
      margin-right: 8px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
}
</style>
